﻿//【进阶】40.C++11(2)
//【头文件包含】
//C++的主要头文件
#include<iostream>//c++的输入输出流
using namespace std;
#include<algorithm>
#include<string>
#include<vector>
#include<list>
//C的主要头文件
//#include<stdio.h>
//#include<stdlib.h>
//#include<assert.h>
//#include<string.h> 


//【命名空间】

//【类声明】
struct Goods
{
	string _name;
	double _price;
};
struct Compare
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price <= gr._price;
	}
};

//【函数声明】
void Test1();void Test2();void Test3();


//【主函数】
int main()
{
	cout << "****主函数开始****" << endl;
	Test1();
	Test2();
	Test3();
	cout << "****主函数结束****" << endl;
	return 0;
}

//【函数定义】

/*测试用例*/void Test1()
{
	cout << "****测试用例开始****"<< endl;
	// 最简单的lambda表达式, 该lambda表达式没有任何意义
	[] {};

	// 省略参数列表和返回值类型，返回值类型由编译器推导为int
	int a = 3, b = 4;


	auto add1 = [](int x1, int x2)->int {return x1 + x2;};
	cout << add1(a, b) << endl;

	//直接捕捉(复制捕捉)
	auto add2 = [a, b]()->int {return a + b;};
	cout << add2() << endl;

	//全部捕捉
	auto add3 = [=] {return a + 3; };
	cout << add3() << endl;

	// 省略了返回值类型，无返回值类型
	auto add4 = [&](int c) {b = a + c; };
	add4(10);
	cout << a << " " << b << endl;

	//各部分都很完善的lambda函数
	auto add5 = [=, &b](int c)->int {return b += a + c; };
	cout << add5(10) << endl;
	
	
	cout << "****测试用例结束****" << endl << endl;
}

/*测试用例*/void Test2()
{
	cout << "****测试用例开始****" << endl;
	Goods gds1[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
	sort(gds1, gds1 + sizeof(gds1) / sizeof(gds1[0]), Compare());

	Goods gds2[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
	sort(gds2, gds2 + sizeof(gds2) / sizeof(gds2[0]), [](const Goods& l, const Goods& r)
		->bool
		{
			return l._price < r._price;
		});


	cout << "****测试用例结束****" << endl<<endl;
}

/*测试用例*/void Test3()
{
	cout << "****测试用例开始****" << endl;

	cout << "****测试用例结束****" << endl << endl;
}




//【笔记】
//【进阶】40.C++11(2)
	//右值引用
		//移动语义
		// 在C++11中如果需要实现移动语义，必须使用右值引用。当类中涉及到资源管理时，用户必须显式定义自己的移动构造。
		// 右值引用引用左值，通过move函数将左值转化为右值。
		// 在实际工程中总会出现传值返回的场景，对于复杂类的对象，过多深拷贝负载过高，所以使用移动拷贝会提高效率
		// 右值引用作为函数参数
		//总结
			//左值引用和右值引用的本质都是为了减少拷贝提高效率
			//右值引用做参数和返回值是减少拷贝本质是结合利用了移动构造和移动赋值
			// 左值引用是在传参时减少拷贝，函数内部的拷贝不能减少，而右值引用可以解决这个缺陷
			// 左值引用时如果返回值出作用域不存在就不能引用返回，所以说右值引用解决了左值引用的一些缺陷
		//【完美转发】
			// 是指在函数模板中，完全依照模板的参数的类型，将参数传递给函数模板中调用的另外一个函数。
			// 右值引用在第二次之后的参数传递中属性被丢失，需要使用forward函数来实现完美转发：std::forward<T>
			// 函数模板在向其他函数传递自身形参时，如果实参是左值，它就应被转发为左值；如果实参是右值，它就应被转发为右值。
			// 目的是为保留在其他函数针对转发而来的参数的左右值属性进行不同处理：参数为左值时实施拷贝语义；参数为右值时实施移动语义
	//lambda表达式 
		//本质是一个函数
		// lambda表达式书写格式：
		// [capture-list] (parameters) mutable -> return-type { statement }
			// 捕捉列表 - [capture-list]
				// 在lambda表达式最前，编译器根据[]判断是否构成lambda函数，[]内的值可以捕捉上下文变量供lambda使用
				// 捕捉列表说明：语法上捕捉列表可由多个捕捉项组成，并以逗号分割
					// [var]：表示值传递方式捕捉变量var
					// [=]：表示值传递方式捕获所有父作用域中的变量(包括this)，父作用域指包含lambda函数的语句块
					// [&var]：表示引用传递捕捉变量var
					// [&]：表示引用传递捕捉所有父作用域中的变量(包括this)
					// [this]：表示值传递方式捕捉当前的this指针
			// 参数列表 - (parameters)
				// 与普通函数的参数列表一致，不传参则省略
			// 取消常量性 - mutable
				// 默认情况下lambda函数总是const函数，显示mutable可以取消常量属性，使用时则不能省略参数列表
			// 返回值类型 - ->returntype
				// 没返回值或返回值类型明确是可以省略，有编译器进行推导
			// 函数体 - {statement}
				// 函数体内为函数实现代码，除可使用参数列表的参数外还可使用所有捕获到的变量

		









